#pragma once
#include <iostream>
#include "Sem.hpp"
#include "Mutex.hpp"
#include <vector>

using namespace SemModule;
using namespace MutexModule;

const int defaultcap = 5; // 先搞5个空间

template <class T>

class RingQueue
{
public:
    RingQueue(int cap = defaultcap) // _sem_blank(cap)->环形队列最开始都是空的
        : _rq(cap), _cap(cap), _sem_data(0), _c_step(0), _sem_blank(cap), _p_step(0)
    {
    }
    // 生产数据
    void Equeue(const T& in)
    {
        // 1.生产者，申请信号量，空位置信号量减1
        _sem_blank.P();
        {
            // 访问临界资源，要加锁，针对多生产者
            LockGuard lockguard(_pmutex);
            // 2.生产
            _rq[_p_step] = in;
            // 3.更新下标
            _p_step++;
            // 4.维持环性特性
            _p_step %= _cap;
        }
        // 生产了一个数据，数据信号量加1
        _sem_data.V();
    }

    // 消费数据
    void Pop(T* out) // 输出型参数
    {
        // 1.消费者，申请数据信号量
        _sem_data.P();
        {
            LockGuard lockguard(_cmutex);
            // 2.消费
            *out = _rq[_c_step];
            // 3.更新下标
            _c_step++;
            // 4.维持环形特性
            _c_step %= _cap;
        }
        _sem_blank.V();
    }
private:
    std::vector<T> _rq; // 这是临界资源，所以需要加锁保护
    int _cap;      // 临界资源的大小

    // 消费者
    Sem _sem_data; // 资源: 位置上的数据
    int _c_step;   // 消费者目前所在的位置

    // 生产者
    Sem _sem_blank; // 资源: 空位置
    int _p_step;    // 消费者目前所在的位置

    // 维护多生产和多消费: 2把锁，单生产和单消费就无需使用锁
    // 生产者之间是互斥的(在这个位置上生产数据)，消费者之间是互斥的
    Mutex _cmutex;
    Mutex _pmutex;
};